import configparser
import functools
import inspect
import os
import sys

from datetime import datetime

import win32con
import win32gui

from PyQt5.QtWidgets import QApplication
from openGaussMigrate.common.com_log import ComLog


class Base:
    def __init__(self):
        self.log = ComLog(self.__class__.__name__)

    @staticmethod
    def get_node_yaml(file_path, lable, key):
        """
        读取配置文件
        :param file_path: 配置文件路径
        :param lable: 标签
        :param key: 标签参数名
        :return: 标签参数值
        """
        config = configparser.ConfigParser()
        config.read(file_path, encoding="utf-8")
        res = config.get(lable, key)
        return eval(res)

    @staticmethod
    def retry(target=None, max_n=1, func_prefix="test"):
        """
        :param target: 被装饰的对象，可以是class, function
        :param max_n: 重试次数，没有包含必须有的第一次执行
        :param func_prefix: 当装饰class时，可以用于标记哪些测试方法会被自动装饰
        :return: wrapped class 或 wrapped function
        """

        def decorator(func_or_cls):
            if inspect.isfunction(func_or_cls):
                @functools.wraps(func_or_cls)
                def wrapper(*args, **kwargs):
                    n = 0
                    while n <= max_n:
                        try:
                            n += 1
                            func_or_cls(*args, **kwargs)
                            return
                        except Exception as e:
                            if n <= max_n:
                                args[0].tearDown()
                                args[0].setUp()
                            else:
                                print(str(e))
                                raise e

                return wrapper
            elif inspect.isclass(func_or_cls):
                for name, func in list(func_or_cls.__dict__.items()):
                    if inspect.isfunction(func) and name.startswith(
                            func_prefix):
                        setattr(func_or_cls, name, decorator(func))
                return func_or_cls
            else:
                raise AttributeError

        if target:
            return decorator(target)
        else:
            return decorator

    def get_all_handle(self):
        """
        获取所有窗口句柄
        :return:窗口句柄列表
        """
        handle_list = list()
        win32gui.EnumWindows(lambda handle, param: param.append(handle),
                             handle_list)
        self.log.info([win32gui.GetWindowText(h) for h in handle_list])
        return handle_list

    @staticmethod
    def save_img_when_err(title='openGauss DataKit - Google Chrome',
                          cls_name=None):
        """
        函数异常时截图
        :param title:窗口标题，可通过get_all_handle查看
        :param cls_name:类名，不为空时以类名创建目录存放截图
        :return:wrapped function
        """

        def decorator(func):
            def wrapper(self, *args, **kwargs):
                try:
                    func(self, *args, **kwargs)
                except Exception as e:
                    tm = datetime.now().strftime('%Y%m%d_%H%M%S')
                    if cls_name:
                        img_dir = os.path.join(os.getcwd(), 'img', cls_name)
                    else:
                        img_dir = os.path.join(os.getcwd(), 'img')
                    img_name = f'{func.__name__}_{tm}.png'
                    img_path = os.path.join(img_dir, img_name)
                    os.makedirs(img_dir, exist_ok=True)
                    handle = win32gui.FindWindow(None, title)
                    app = QApplication(sys.argv)
                    screen = QApplication.primaryScreen()
                    img = screen.grabWindow(handle).toImage()
                    img.save(img_path)
                    app.quit()
                    raise e

            return wrapper

        return decorator

    @staticmethod
    def upload(fpath):
        """
        上传文件，fpath指定文件路径
        :param fpath: 待上传的文件路径
        :return: 无
        """
        # 一级顶层窗口，此处title为上传窗口名称，浏览器不一样上传窗口名称不一样
        dialog = win32gui.FindWindow(None, '打开')
        # 二级窗口
        combo_box_ex32 = win32gui.FindWindowEx(
            dialog, 0, "ComboBoxEx32", None)
        # 三级窗口
        combo_box = win32gui.FindWindowEx(
            combo_box_ex32, 0, "ComboBox", None)
        # 四级窗口
        edit = win32gui.FindWindowEx(combo_box, 0, 'Edit', None)
        button = win32gui.FindWindowEx(dialog, 0, 'Button', None)
        # 执行操作 输入文件路径
        win32gui.SendMessage(edit, win32con.WM_SETTEXT, None, fpath)
        # 点击打开上传文件
        win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1, button)
